// /////////////////////////////////////////////////////////////////////////////
//
// Name:            ParticleSysComponent.cpp
// Author:          Michael Bartsch (ZCCdark203)
//
// Desc :           Component wrapper of Irrlicht's IParticleSystemSceneNode.
//
// License:         Copyright (C) 2009 Michael Bartsch and Contributors
//
//                  This program is free software: you can redistribute it
//                  and/or modify it under the terms of the zlib/libpng License.
//                  See main.cpp for conditions of distribution and use.
//
// /////////////////////////////////////////////////////////////////////////////

// Include files
#include "ParticleSysComponent.h"
#include "../../core/GameManager.h"


// ParticleSysComponent class
// ParticleSysComponent constructor (default).
ParticleSysComponent::ParticleSysComponent(Entity *parent, const vector3df &scale)
: SceneComponent(parent, true)
{
    if(pParent != NULL)
    {
       // Get pointers to needed sub-systems of the Game Manager.
       ISceneManager *pSceneMgr = GameManager::Instance()->getSceneManager();

       // Create the s32ernal scene node.
       mParticleSystemSN = pSceneMgr->addParticleSystemSceneNode(true, 0, parent->getID(),
                                                                 parent->getAbsolutePosition(),
                                                                 parent->getAbsoluteRotation(),
                                                                 scale);
       mSceneNode = mParticleSystemSN;

       // Set-up s32ernal mechanism for collision detection.
       mTriSelector = NULL;
       mMetaSelector = pSceneMgr->createMetaTriangleSelector();
    }
}

// ParticleSysComponent deconstructor.
ParticleSysComponent::~ParticleSysComponent()
{
    if(pParent != NULL)
    {
       mParticleSystemSN->remove();
       mSceneNode = NULL;
    }
}

// Returns a direct pointer to the IParticleSystemSceneNode.
IParticleSystemSceneNode* ParticleSysComponent::getParticleSystemSceneNode()
{
    return mParticleSystemSN;
}

// Adds a new particle effector to the particle system.
void ParticleSysComponent::addAffector(IParticleAffector *affector)
{
    mParticleSystemSN->addAffector(affector);
}

// Adds a point attraction affector.
void ParticleSysComponent::addAttractionAffector(const vector3df &point, f32 speed, bool attract,
                                                 bool affectX, bool affectY, bool affectZ)
{
    IParticleAffector *affector = mParticleSystemSN->createAttractionAffector(point, speed, attract,
                                    affectX, affectY, affectZ);
    mParticleSystemSN->addAffector(affector);
    affector->drop();
}

// Adds a fade out particle affector.
void ParticleSysComponent::addFadeOutParticleAffector(const SColor &targetColor,
                                                      u32 timeNeededToFadeOut)
{
    IParticleAffector *affector = mParticleSystemSN->createFadeOutParticleAffector(targetColor,
                                    timeNeededToFadeOut);
    mParticleSystemSN->addAffector(affector);
    affector->drop();
}

// Adds a gravity affector.
void ParticleSysComponent::addGravityAffector(const vector3df &gravity, u32 timeForceLost)
{
    IParticleAffector *affector = mParticleSystemSN->createGravityAffector(gravity, timeForceLost);
    mParticleSystemSN->addAffector(affector);
    affector->drop();
}

// Adds a rotation affector.
void ParticleSysComponent::addRotationAffector(const vector3df &speed, const vector3df &pivotPoint)
{
    IParticleAffector *affector = mParticleSystemSN->createRotationAffector(speed, pivotPoint);
    mParticleSystemSN->addAffector(affector);
    affector->drop();
}

// Adds a scale particle affector.
void ParticleSysComponent::addScaleParticleAffector(const dimension2df &scaleTo)
{
    IParticleAffector *affector = mParticleSystemSN->createScaleParticleAffector(scaleTo);
    mParticleSystemSN->addAffector(affector);
    affector->drop();
}

// Removes all affectors.
void ParticleSysComponent::removeAffectors()
{
    mParticleSystemSN->removeAllAffectors();
}

// Gets the particle emitter, which creates the particles.
IParticleEmitter* ParticleSysComponent::getEmitter()
{
    return mParticleSystemSN->getEmitter();
}

// Creates a particle emitter for an animated mesh component.
void ParticleSysComponent::setAnimatedMeshSceneNodeEmitter(IAnimatedMeshSceneNode *node,
                                                           bool useNormalDirection,
                                                           const vector3df &direction,
                                                           f32 normalDirectionModifier,
                                                           bool everyMeshVertex,
                                                           u32 minParticlesPerSecond,
                                                           u32 maxParticlesPerSecond,
                                                           const SColor &minStartColor,
                                                           const SColor &maxStartColor,
                                                           u32 lifeTimeMin, u32 lifeTimeMax,
                                                           s32 maxAngleDegrees,
                                                           const dimension2df &minStartSize,
                                                           const dimension2df &maxStartSize)
{
    IParticleEmitter *emitter = mParticleSystemSN->createAnimatedMeshSceneNodeEmitter(node,
                                  useNormalDirection, direction, normalDirectionModifier, -1,
                                  everyMeshVertex, minParticlesPerSecond, maxParticlesPerSecond,
                                  minStartColor, maxStartColor, lifeTimeMin, lifeTimeMax,
                                  maxAngleDegrees, minStartSize, maxStartSize);
    mParticleSystemSN->setEmitter(emitter);
    emitter->drop();
}

// Sets a box particle emitter.
void ParticleSysComponent::setBoxEmitter(const aabbox3df &box, const vector3df &direction,
                                         u32 minParticlesPerSecond, u32 maxParticlesPerSecond,
                                         const SColor &minStartColor, const SColor &maxStartColor,
                                         u32 lifeTimeMin, u32 lifeTimeMax, s32 maxAngleDegrees,
                                         const dimension2df &minStartSize,
                                         const dimension2df &maxStartSize)
{
    IParticleEmitter *emitter = mParticleSystemSN->createBoxEmitter(box, direction,
                                  minParticlesPerSecond, maxParticlesPerSecond, minStartColor,
                                  maxStartColor, lifeTimeMin, lifeTimeMax, maxAngleDegrees,
                                  minStartSize, maxStartSize);
    mParticleSystemSN->setEmitter(emitter);
    emitter->drop();
}

// Sets a particle emitter for emitting from a cylinder.
void ParticleSysComponent::setCylinderEmitter(const vector3df &center, f32 radius,
                                              const vector3df &normal, f32 length,
                                              bool outlineOnly, const vector3df &direction,
                                              u32 minParticlesPerSecond, u32 maxParticlesPerSecond,
                                              const SColor &minStartColor,
                                              const SColor &maxStartColor,
                                              u32 lifeTimeMin, u32 lifeTimeMax, s32 maxAngleDegrees,
                                              const dimension2df &minStartSize,
                                              const dimension2df &maxStartSize)
{
    IParticleEmitter *emitter = mParticleSystemSN->createCylinderEmitter(center, radius, normal,
                                  length, outlineOnly, direction, minParticlesPerSecond,
                                  maxParticlesPerSecond, minStartColor, maxStartColor, lifeTimeMin,
                                  lifeTimeMax, maxAngleDegrees, minStartSize, maxStartSize);
    mParticleSystemSN->setEmitter(emitter);
    emitter->drop();
}

// Sets the particle emitter, which creates the particles.
void ParticleSysComponent::setEmitter(IParticleEmitter *emitter)
{
    mParticleSystemSN->setEmitter(emitter);
}

// Sets a particle emitter for the loaded mesh.
void ParticleSysComponent::setMeshEmitter(const std::string &fileName, bool useNormalDirection,
                                          const vector3df &direction, f32 normalDirectionModifier,
                                          bool everyMeshVertex, u32 minParticlesPerSecond,
                                          u32 maxParticlesPerSecond, const SColor &minStartColor,
                                          const SColor &maxStartColor, u32 lifeTimeMin,
                                          u32 lifeTimeMax, s32 maxAngleDegrees,
                                          const dimension2df &minStartSize,
                                          const dimension2df &maxStartSize)
{
    IMesh *mesh = GameManager::Instance()->getSceneManager()->getMesh(fileName.c_str());

    if(mesh)
    {
       IParticleEmitter *emitter = mParticleSystemSN->createMeshEmitter(mesh, useNormalDirection,
                                  direction, normalDirectionModifier, -1, everyMeshVertex,
                                  minParticlesPerSecond, maxParticlesPerSecond,
                                  minStartColor, maxStartColor, lifeTimeMin, lifeTimeMax,
                                  maxAngleDegrees, minStartSize, maxStartSize);
       mParticleSystemSN->setEmitter(emitter);
       emitter->drop();
    }
}

// Sets a particle emitter for the loaded mesh.
void ParticleSysComponent::setMeshEmitter(IMesh *mesh, bool useNormalDirection,
                                          const vector3df &direction,
                                          f32 normalDirectionModifier, bool everyMeshVertex,
                                          u32 minParticlesPerSecond, u32 maxParticlesPerSecond,
                                          const SColor &minStartColor, const SColor &maxStartColor,
                                          u32 lifeTimeMin, u32 lifeTimeMax, s32 maxAngleDegrees,
                                          const dimension2df &minStartSize,
                                          const dimension2df &maxStartSize)
{
    IParticleEmitter *emitter = mParticleSystemSN->createMeshEmitter(mesh, useNormalDirection,
                                  direction, normalDirectionModifier, -1, everyMeshVertex,
                                  minParticlesPerSecond, maxParticlesPerSecond,
                                  minStartColor, maxStartColor, lifeTimeMin, lifeTimeMax,
                                  maxAngleDegrees, minStartSize, maxStartSize);
    mParticleSystemSN->setEmitter(emitter);
    emitter->drop();
}

// Sets a point particle emitter.
void ParticleSysComponent::setPointEmitter(const vector3df &direction,
                                           u32 minParticlesPerSecond, u32 maxParticlesPerSecond,
                                           const SColor &minStartColor, const SColor &maxStartColor,
                                           u32 lifeTimeMin, u32 lifeTimeMax, s32 maxAngleDegrees,
                                           const dimension2df &minStartSize,
                                           const dimension2df &maxStartSize)
{
    IParticleEmitter *emitter = mParticleSystemSN->createPointEmitter(direction,
                                  minParticlesPerSecond, maxParticlesPerSecond, minStartColor,
                                  maxStartColor, lifeTimeMin, lifeTimeMax, maxAngleDegrees,
                                  minStartSize, maxStartSize);
    mParticleSystemSN->setEmitter(emitter);
    emitter->drop();
}

// Sets a ring particle emitter.
void ParticleSysComponent::setRingEmitter(const vector3df &center, f32 radius,
                                          f32 ringThickness, const vector3df &direction,
                                          u32 minParticlesPerSecond, u32 maxParticlesPerSecond,
                                          const SColor &minStartColor, const SColor &maxStartColor,
                                          u32 lifeTimeMin, u32 lifeTimeMax, s32 maxAngleDegrees,
                                          const dimension2df &minStartSize,
                                          const dimension2df &maxStartSize)
{
    IParticleEmitter *emitter = mParticleSystemSN->createRingEmitter(center, radius, ringThickness,
                                  direction, minParticlesPerSecond, maxParticlesPerSecond,
                                  minStartColor, maxStartColor, lifeTimeMin, lifeTimeMax,
                                  maxAngleDegrees, minStartSize, maxStartSize);
    mParticleSystemSN->setEmitter(emitter);
    emitter->drop();
}

// Sets a sphere particle emitter.
void ParticleSysComponent::setSphereEmitter(const vector3df &center, f32 radius,
                                            const vector3df &direction,
                                            u32 minParticlesPerSecond, u32 maxParticlesPerSecond,
                                            const SColor &minStartColor,
                                            const SColor &maxStartColor,
                                            u32 lifeTimeMin, u32 lifeTimeMax, s32 maxAngleDegrees,
                                            const dimension2df &minStartSize,
                                            const dimension2df &maxStartSize)
{
    IParticleEmitter *emitter = mParticleSystemSN->createSphereEmitter(center, radius, direction,
                                  minParticlesPerSecond, maxParticlesPerSecond, minStartColor,
                                  maxStartColor, lifeTimeMin, lifeTimeMax, maxAngleDegrees,
                                  minStartSize, maxStartSize);
    mParticleSystemSN->setEmitter(emitter);
    emitter->drop();
}

// Sets if the particles should be global.
void ParticleSysComponent::setParticlesAreGlobal(bool value)
{
    mParticleSystemSN->setParticlesAreGlobal(value);
}

// Sets the size of all particles.
void ParticleSysComponent::setParticleSize(const dimension2df &size)
{
    mParticleSystemSN->setParticleSize(size);
}

// Parses for a ParticleSYsComponent.
bool ParticleSysComponent::parseXML(IXMLReader *file, Entity *entity)
{
    // Forward declaration.
    ParticleSysComponent *component = NULL;

    // Are we dealing with a ParticleSysComponent?
    if(file->getNodeType() == io::EXN_ELEMENT)
    {
       if(stringw("ParticleSysComponent") == file->getNodeName())
       {
          // Initialise the component.
          component = new ParticleSysComponent(entity);
       }
    }

    if(component == NULL)
      return false;

    // Continue parsing the file.
    while(file->read())
    {
       switch(file->getNodeType())
       {
          case io::EXN_ELEMENT:

             // <AttractionAffector>
             if(stringw("AttractionAffector") == file->getNodeName())
             {
                // Retrieve required variables from internal loop.
                vector3df point;
                f32 speed = 1.0f;
                bool attract = true;
                bool affectX = true;
                bool affectY = true;
                bool affectZ = true;

                bool doneParsing = false;

                while(file->read() && !doneParsing)
                {
                   switch(file->getNodeType())
                   {
                      case io::EXN_ELEMENT:

                         // <point>
                         if(stringw("point") == file->getNodeName())
                         {
                            point = vector3df( file->getAttributeValueAsFloat(L"x"),
                                               file->getAttributeValueAsFloat(L"y"),
                                               file->getAttributeValueAsFloat(L"z") );
                         }

                         // <speed>
                         else if(stringw("speed") == file->getNodeName())
                           speed = file->getAttributeValueAsFloat(L"value");

                         // <attract>
                         else if(stringw("attract") == file->getNodeName())
                         {
                            stringc value = file->getAttributeValue(L"value");
                            attract = (value == "true") ? true : false ;
                         }

                         // <affectX>
                         else if(stringw("affectX") == file->getNodeName())
                         {
                            stringc value = file->getAttributeValue(L"value");
                            affectX = (value == "true") ? true : false ;
                         }

                         // <affectY>
                         else if(stringw("affectY") == file->getNodeName())
                         {
                            stringc value = file->getAttributeValue(L"value");
                            affectY = (value == "true") ? true : false ;
                         }

                         // <affectZ>
                         else if(stringw("affectZ") == file->getNodeName())
                         {
                            stringc value = file->getAttributeValue(L"value");
                            affectZ = (value == "true") ? true : false ;
                         }

                         break;

                      case io::EXN_ELEMENT_END:

                         // </AttractionAffector>
                         if(stringw("AttractionAffector") == file->getNodeName())
                           doneParsing = true;

                         break;

                      default:

                         break;
                   }
                }

                // We create the affector.
                component->addAttractionAffector(point, speed, attract, affectX, affectY, affectZ);
             }

             // <FadeOutParticleAffector>
             else if(stringw("FadeOutParticleAffector") == file->getNodeName())
             {
                // Retrieve required variables from internal loop.
                SColor targetColor = SColor(0, 0, 0, 0);
                u32 timeNeededToFadeOut = 1000;

                bool doneParsing = false;

                while(file->read() && !doneParsing)
                {
                   switch(file->getNodeType())
                   {
                      case io::EXN_ELEMENT:

                         // <targetColor>
                         if(stringw("targetColor") == file->getNodeName())
                         {
                            targetColor = SColor( file->getAttributeValueAsInt(L"a"),
                                                  file->getAttributeValueAsInt(L"r"),
                                                  file->getAttributeValueAsInt(L"g"),
                                                  file->getAttributeValueAsInt(L"b") );
                         }

                         else if(stringw("timeNeededToFadeOut") == file->getNodeName())
                           timeNeededToFadeOut = file->getAttributeValueAsInt(L"value");

                         break;

                      case io::EXN_ELEMENT_END:

                         // </FadeOutParticleAffector>
                         if(stringw("FadeOutParticleAffector") == file->getNodeName())
                           doneParsing = true;

                         break;

                      default:

                         break;
                   }
                }

                // We create the affector.
                component->addFadeOutParticleAffector(targetColor, timeNeededToFadeOut);
             }

             // <GravityAffector>
             else if(stringw("GravityAffector") == file->getNodeName())
             {
                // Retrieve required variables from internal loop.
                vector3df gravity = vector3df(0.0f,-0.03f, 0.0f);
                u32 timeForceLost = 1000;

                bool doneParsing = false;

                while(file->read() && !doneParsing)
                {
                   switch(file->getNodeType())
                   {
                      case io::EXN_ELEMENT:

                         // <gravity>
                         if(stringw("gravity") == file->getNodeName())
                         {
                            gravity = vector3df( file->getAttributeValueAsFloat(L"x"),
                                                 file->getAttributeValueAsFloat(L"y"),
                                                 file->getAttributeValueAsFloat(L"z") );
                         }

                         else if(stringw("timeForceLost") == file->getNodeName())
                           timeForceLost = file->getAttributeValueAsInt(L"value");

                         break;

                      case io::EXN_ELEMENT_END:

                         // </GravityAffector>
                         if(stringw("GravityAffector") == file->getNodeName())
                           doneParsing = true;

                         break;

                      default:

                         break;
                   }
                }

                // We create the affector.
                component->addGravityAffector(gravity, timeForceLost);
             }

             // <RotationAffector>
             else if(stringw("RotationAffector") == file->getNodeName())
             {
                // Retrieve required variables from internal loop.
                vector3df speed = vector3df(5.0f, 5.0f, 5.0f);
                vector3df pivotPoint = vector3df(0.0f, 0.0f, 0.0f);

                bool doneParsing = false;

                while(file->read() && !doneParsing)
                {
                   switch(file->getNodeType())
                   {
                      case io::EXN_ELEMENT:

                         // <speed>
                         if(stringw("speed") == file->getNodeName())
                         {
                            speed = vector3df( file->getAttributeValueAsFloat(L"x"),
                                               file->getAttributeValueAsFloat(L"y"),
                                               file->getAttributeValueAsFloat(L"z") );
                         }

                         // <pivotPoint>
                         else if(stringw("pivotPoint") == file->getNodeName())
                         {
                            pivotPoint = vector3df( file->getAttributeValueAsFloat(L"x"),
                                                    file->getAttributeValueAsFloat(L"y"),
                                                    file->getAttributeValueAsFloat(L"z") );
                         }

                         break;

                      case io::EXN_ELEMENT_END:

                         // </RotationAffector>
                         if(stringw("RotationAffector") == file->getNodeName())
                           doneParsing = true;

                         break;

                      default:

                         break;
                   }
                }

                // We create the affector.
                component->addRotationAffector(speed, pivotPoint);
             }

             // <ScaleParticleAffector>
             else if(stringw("ScaleParticleAffector") == file->getNodeName())
             {
                // Retrieve required variables from internal loop.
                dimension2df scaleTo = dimension2df(1.0f, 1.0f);

                bool doneParsing = false;

                while(file->read() && !doneParsing)
                {
                   switch(file->getNodeType())
                   {
                      case io::EXN_ELEMENT:

                         // <scaleTo>
                         if(stringw("scaleTo") == file->getNodeName())
                         {
                            scaleTo = dimension2df( file->getAttributeValueAsFloat(L"width"),
                                                    file->getAttributeValueAsFloat(L"height") );
                         }

                         break;

                      case io::EXN_ELEMENT_END:

                         // </ScaleParticleAffector>
                         if(stringw("ScaleParticleAffector") == file->getNodeName())
                           doneParsing = true;

                         break;

                      default:

                         break;
                   }
                }

                // We create the affector.
                component->addScaleParticleAffector(scaleTo);
             }

             // <MeshEmitter>
             else if(stringw("MeshEmitter") == file->getNodeName())
             {
                // Retrieve required variables from internal loop.
                std::string fileName;
                bool useNormalDirection = true;
                vector3df direction = vector3df(0.0f, 0.03f, 0.0f);
                f32 normalDirectionModifier = 100.0f;
                bool everyMeshVertex = false;
                u32 minParticlesPerSecond = 5;
                u32 maxParticlesPerSecond = 10;
                SColor minStartColor = SColor(255, 0, 0, 0);
                SColor maxStartColor = SColor(255, 255, 255, 255);
                u32 lifeTimeMin = 2000;
                u32 lifeTimeMax = 4000;
                s32 maxAngleDegrees = 0;
                dimension2df minStartSize = dimension2df(5.0f, 5.0f);
                dimension2df maxStartSize = dimension2df(5.0f, 5.0f);

                bool doneParsing = false;

                while(file->read() && !doneParsing)
                {
                   switch(file->getNodeType())
                   {
                      case io::EXN_ELEMENT:

                         // <fileName>
                         if(stringw("fileName") == file->getNodeName())
                         {
                            stringc value = file->getAttributeValue(L"value");
                            fileName = value.c_str();
                         }

                         // <useNormalDirection>
                         else if(stringw("useNormalDirection") == file->getNodeName())
                         {
                            stringc value = file->getAttributeValue(L"value");
                            useNormalDirection = (value == "true") ? true : false ;
                         }

                         // <direction>
                         else if(stringw("direction") == file->getNodeName())
                         {
                            direction = vector3df( file->getAttributeValueAsFloat(L"x"),
                                                   file->getAttributeValueAsFloat(L"y"),
                                                   file->getAttributeValueAsFloat(L"z") );
                         }

                         // <normalDirectionModifier>
                         else if(stringw("normalDirectionModifier") == file->getNodeName())
                           normalDirectionModifier = file->getAttributeValueAsFloat(L"value");

                         // <everyMeshVertex>
                         else if(stringw("everyMeshVertex") == file->getNodeName())
                         {
                            stringc value = file->getAttributeValue(L"value");
                            everyMeshVertex = (value == "true") ? true : false ;
                         }

                         // <minParticlesPerSecond>
                         else if(stringw("minParticlesPerSecond") == file->getNodeName())
                           minParticlesPerSecond = file->getAttributeValueAsInt(L"value");

                         // <maxParticlesPerSecond>
                         else if(stringw("maxParticlesPerSecond") == file->getNodeName())
                           maxParticlesPerSecond = file->getAttributeValueAsInt(L"value");

                         // <minStartColor>
                         else if(stringw("minStartColor") == file->getNodeName())
                         {
                            minStartColor = SColor( file->getAttributeValueAsInt(L"a"),
                                                    file->getAttributeValueAsInt(L"r"),
                                                    file->getAttributeValueAsInt(L"g"),
                                                    file->getAttributeValueAsInt(L"b") );
                         }

                         // <maxStartColor>
                         else if(stringw("maxStartColor") == file->getNodeName())
                         {
                            maxStartColor = SColor( file->getAttributeValueAsInt(L"a"),
                                                    file->getAttributeValueAsInt(L"r"),
                                                    file->getAttributeValueAsInt(L"g"),
                                                    file->getAttributeValueAsInt(L"b") );
                         }

                         // <lifeTimeMin>
                         else if(stringw("lifeTimeMin") == file->getNodeName())
                           lifeTimeMin = file->getAttributeValueAsInt(L"value");

                         // <lifeTimeMin>
                         else if(stringw("lifeTimeMax") == file->getNodeName())
                           lifeTimeMax = file->getAttributeValueAsInt(L"value");

                         // <maxAngleDegrees>
                         else if(stringw("maxAngleDegrees") == file->getNodeName())
                           maxAngleDegrees = file->getAttributeValueAsInt(L"value");

                         // <minStartSize>
                         else if(stringw("minStartSize") == file->getNodeName())
                         {
                            minStartSize = dimension2df( file->getAttributeValueAsFloat(L"width"),
                                                         file->getAttributeValueAsFloat(L"height"));
                         }

                         // <maxStartSize>
                         else if(stringw("maxStartSize") == file->getNodeName())
                         {
                            maxStartSize = dimension2df( file->getAttributeValueAsFloat(L"width"),
                                                         file->getAttributeValueAsFloat(L"height"));
                         }

                         break;

                      case io::EXN_ELEMENT_END:

                         // </MeshEmitter>
                         if(stringw("MeshEmitter") == file->getNodeName())
                           doneParsing = true;

                         break;

                      default:

                         break;
                   }
                }

                // We create the emitter.
                component->setMeshEmitter(fileName, useNormalDirection, direction,
                             normalDirectionModifier, everyMeshVertex, minParticlesPerSecond,
                             maxParticlesPerSecond, minStartColor, maxStartColor, lifeTimeMin,
                             lifeTimeMax, maxAngleDegrees, minStartSize, maxStartSize);
             }

             // <BoxEmitter>
             else if(stringw("BoxEmitter") == file->getNodeName())
             {
                // Retrieve required variables from internal loop.
                aabbox3df box = aabbox3df(-10, 28,-10, 10, 30, 10);
                vector3df direction = vector3df(0.0f, 0.03f, 0.0f);
                u32 minParticlesPerSecond = 5;
                u32 maxParticlesPerSecond = 10;
                SColor minStartColor = SColor(255, 0, 0, 0);
                SColor maxStartColor = SColor(255, 255, 255, 255);
                u32 lifeTimeMin = 2000;
                u32 lifeTimeMax = 4000;
                s32 maxAngleDegrees = 0;
                dimension2df minStartSize = dimension2df(5.0f, 5.0f);
                dimension2df maxStartSize = dimension2df(5.0f, 5.0f);

                bool doneParsing = false;

                while(file->read() && !doneParsing)
                {
                   switch(file->getNodeType())
                   {
                      case io::EXN_ELEMENT:

                         // <box>
                         if(stringw("scaleTo") == file->getNodeName())
                         {
                            box = aabbox3df( file->getAttributeValueAsFloat(L"minX"),
                                             file->getAttributeValueAsFloat(L"minY"),
                                             file->getAttributeValueAsFloat(L"minZ"),
                                             file->getAttributeValueAsFloat(L"maxX"),
                                             file->getAttributeValueAsFloat(L"maxY"),
                                             file->getAttributeValueAsFloat(L"maxZ") );
                         }

                         // <direction>
                         else if(stringw("direction") == file->getNodeName())
                         {
                            direction = vector3df( file->getAttributeValueAsFloat(L"x"),
                                                   file->getAttributeValueAsFloat(L"y"),
                                                   file->getAttributeValueAsFloat(L"z") );
                         }

                         // <minParticlesPerSecond>
                         else if(stringw("minParticlesPerSecond") == file->getNodeName())
                           minParticlesPerSecond = file->getAttributeValueAsInt(L"value");

                         // <maxParticlesPerSecond>
                         else if(stringw("maxParticlesPerSecond") == file->getNodeName())
                           maxParticlesPerSecond = file->getAttributeValueAsInt(L"value");

                         // <minStartColor>
                         else if(stringw("minStartColor") == file->getNodeName())
                         {
                            minStartColor = SColor( file->getAttributeValueAsInt(L"a"),
                                                    file->getAttributeValueAsInt(L"r"),
                                                    file->getAttributeValueAsInt(L"g"),
                                                    file->getAttributeValueAsInt(L"b") );
                         }

                         // <maxStartColor>
                         else if(stringw("maxStartColor") == file->getNodeName())
                         {
                            maxStartColor = SColor( file->getAttributeValueAsInt(L"a"),
                                                    file->getAttributeValueAsInt(L"r"),
                                                    file->getAttributeValueAsInt(L"g"),
                                                    file->getAttributeValueAsInt(L"b") );
                         }

                         // <lifeTimeMin>
                         else if(stringw("lifeTimeMin") == file->getNodeName())
                           lifeTimeMin = file->getAttributeValueAsInt(L"value");

                         // <lifeTimeMin>
                         else if(stringw("lifeTimeMax") == file->getNodeName())
                           lifeTimeMax = file->getAttributeValueAsInt(L"value");

                         // <maxAngleDegrees>
                         else if(stringw("maxAngleDegrees") == file->getNodeName())
                           maxAngleDegrees = file->getAttributeValueAsInt(L"value");

                         // <minStartSize>
                         else if(stringw("minStartSize") == file->getNodeName())
                         {
                            minStartSize = dimension2df( file->getAttributeValueAsFloat(L"width"),
                                                         file->getAttributeValueAsFloat(L"height"));
                         }

                         // <maxStartSize>
                         else if(stringw("maxStartSize") == file->getNodeName())
                         {
                            maxStartSize = dimension2df( file->getAttributeValueAsFloat(L"width"),
                                                         file->getAttributeValueAsFloat(L"height"));
                         }

                         break;

                      case io::EXN_ELEMENT_END:

                         // </BoxEmitter>
                         if(stringw("BoxEmitter") == file->getNodeName())
                           doneParsing = true;

                         break;

                      default:

                         break;
                   }
                }

                // We create the emitter
                component->setBoxEmitter(box, direction, minParticlesPerSecond,
                             maxParticlesPerSecond, minStartColor, maxStartColor, lifeTimeMin,
                             lifeTimeMax, maxAngleDegrees, minStartSize, maxStartSize);
             }

             // <CylinderEmitter>
             else if(stringw("CylinderEmitter") == file->getNodeName())
             {
                // Retrieve required variables from internal loop.
                vector3df center;
                f32 radius;
                vector3df normal;
                f32 length;
                bool outlineOnly = false;
                vector3df direction = vector3df(0.0f, 0.03f, 0.0f);
                u32 minParticlesPerSecond = 5;
                u32 maxParticlesPerSecond = 10;
                SColor minStartColor = SColor(255, 0, 0, 0);
                SColor maxStartColor = SColor(255, 255, 255, 255);
                u32 lifeTimeMin = 2000;
                u32 lifeTimeMax = 4000;
                s32 maxAngleDegrees = 0;
                dimension2df minStartSize = dimension2df(5.0f, 5.0f);
                dimension2df maxStartSize = dimension2df(5.0f, 5.0f);

                bool doneParsing = false;

                while(file->read() && !doneParsing)
                {
                   switch(file->getNodeType())
                   {
                      case io::EXN_ELEMENT:

                         // <center>
                         if(stringw("center") == file->getNodeName())
                         {
                            center = vector3df( file->getAttributeValueAsFloat(L"x"),
                                                file->getAttributeValueAsFloat(L"y"),
                                                file->getAttributeValueAsFloat(L"z") );
                         }

                         // <radius>
                         else if(stringw("radius") == file->getNodeName())
                           radius = file->getAttributeValueAsFloat(L"value");

                         // <normal>
                         else if(stringw("normal") == file->getNodeName())
                         {
                            normal = vector3df( file->getAttributeValueAsFloat(L"x"),
                                                file->getAttributeValueAsFloat(L"y"),
                                                file->getAttributeValueAsFloat(L"z") );
                         }

                         // <length>
                         else if(stringw("length") == file->getNodeName())
                           length = file->getAttributeValueAsFloat(L"value");

                         // <outlineOnly>
                         else if(stringw("outlineOnly") == file->getNodeName())
                         {
                            stringc value = file->getAttributeValue(L"value");
                            outlineOnly = (value == "true") ? true : false ;
                         }

                         // <direction>
                         else if(stringw("direction") == file->getNodeName())
                         {
                            direction = vector3df( file->getAttributeValueAsFloat(L"x"),
                                                   file->getAttributeValueAsFloat(L"y"),
                                                   file->getAttributeValueAsFloat(L"z") );
                         }

                         // <minParticlesPerSecond>
                         else if(stringw("minParticlesPerSecond") == file->getNodeName())
                           minParticlesPerSecond = file->getAttributeValueAsInt(L"value");

                         // <maxParticlesPerSecond>
                         else if(stringw("maxParticlesPerSecond") == file->getNodeName())
                           maxParticlesPerSecond = file->getAttributeValueAsInt(L"value");

                         // <minStartColor>
                         else if(stringw("minStartColor") == file->getNodeName())
                         {
                            minStartColor = SColor( file->getAttributeValueAsInt(L"a"),
                                                    file->getAttributeValueAsInt(L"r"),
                                                    file->getAttributeValueAsInt(L"g"),
                                                    file->getAttributeValueAsInt(L"b") );
                         }

                         // <maxStartColor>
                         else if(stringw("maxStartColor") == file->getNodeName())
                         {
                            maxStartColor = SColor( file->getAttributeValueAsInt(L"a"),
                                                    file->getAttributeValueAsInt(L"r"),
                                                    file->getAttributeValueAsInt(L"g"),
                                                    file->getAttributeValueAsInt(L"b") );
                         }

                         // <lifeTimeMin>
                         else if(stringw("lifeTimeMin") == file->getNodeName())
                           lifeTimeMin = file->getAttributeValueAsInt(L"value");

                         // <lifeTimeMin>
                         else if(stringw("lifeTimeMax") == file->getNodeName())
                           lifeTimeMax = file->getAttributeValueAsInt(L"value");

                         // <maxAngleDegrees>
                         else if(stringw("maxAngleDegrees") == file->getNodeName())
                           maxAngleDegrees = file->getAttributeValueAsInt(L"value");

                         // <minStartSize>
                         else if(stringw("minStartSize") == file->getNodeName())
                         {
                            minStartSize = dimension2df( file->getAttributeValueAsFloat(L"width"),
                                                         file->getAttributeValueAsFloat(L"height"));
                         }

                         // <maxStartSize>
                         else if(stringw("maxStartSize") == file->getNodeName())
                         {
                            maxStartSize = dimension2df( file->getAttributeValueAsFloat(L"width"),
                                                         file->getAttributeValueAsFloat(L"height"));
                         }

                         break;

                      case io::EXN_ELEMENT_END:

                         // </CylinderEmitter>
                         if(stringw("CylinderEmitter") == file->getNodeName())
                           doneParsing = true;

                         break;

                      default:

                         break;
                   }
                }

                // We create the emitter.
                component->setCylinderEmitter(center, radius, normal, length, outlineOnly,
                             direction, minParticlesPerSecond, maxParticlesPerSecond, minStartColor,
                             maxStartColor, lifeTimeMin, lifeTimeMax, maxAngleDegrees,
                             minStartSize, maxStartSize);
             }

             // <PointEmitter>
             else if(stringw("PointEmitter") == file->getNodeName())
             {
                // Retrieve required variables from internal loop.
                vector3df direction = vector3df(0.0f, 0.03f, 0.0f);
                u32 minParticlesPerSecond = 5;
                u32 maxParticlesPerSecond = 10;
                SColor minStartColor = SColor(255, 0, 0, 0);
                SColor maxStartColor = SColor(255, 255, 255, 255);
                u32 lifeTimeMin = 2000;
                u32 lifeTimeMax = 4000;
                s32 maxAngleDegrees = 0;
                dimension2df minStartSize = dimension2df(5.0f, 5.0f);
                dimension2df maxStartSize = dimension2df(5.0f, 5.0f);

                bool doneParsing = false;

                while(file->read() && !doneParsing)
                {
                   switch(file->getNodeType())
                   {
                      case io::EXN_ELEMENT:

                         // <direction>
                         if(stringw("direction") == file->getNodeName())
                         {
                            direction = vector3df( file->getAttributeValueAsFloat(L"x"),
                                                   file->getAttributeValueAsFloat(L"y"),
                                                   file->getAttributeValueAsFloat(L"z") );
                         }

                         // <minParticlesPerSecond>
                         else if(stringw("minParticlesPerSecond") == file->getNodeName())
                           minParticlesPerSecond = file->getAttributeValueAsInt(L"value");

                         // <maxParticlesPerSecond>
                         else if(stringw("maxParticlesPerSecond") == file->getNodeName())
                           maxParticlesPerSecond = file->getAttributeValueAsInt(L"value");

                         // <minStartColor>
                         else if(stringw("minStartColor") == file->getNodeName())
                         {
                            minStartColor = SColor( file->getAttributeValueAsInt(L"a"),
                                                    file->getAttributeValueAsInt(L"r"),
                                                    file->getAttributeValueAsInt(L"g"),
                                                    file->getAttributeValueAsInt(L"b") );
                         }

                         // <maxStartColor>
                         else if(stringw("maxStartColor") == file->getNodeName())
                         {
                            maxStartColor = SColor( file->getAttributeValueAsInt(L"a"),
                                                    file->getAttributeValueAsInt(L"r"),
                                                    file->getAttributeValueAsInt(L"g"),
                                                    file->getAttributeValueAsInt(L"b") );
                         }

                         // <lifeTimeMin>
                         else if(stringw("lifeTimeMin") == file->getNodeName())
                           lifeTimeMin = file->getAttributeValueAsInt(L"value");

                         // <lifeTimeMin>
                         else if(stringw("lifeTimeMax") == file->getNodeName())
                           lifeTimeMax = file->getAttributeValueAsInt(L"value");

                         // <maxAngleDegrees>
                         else if(stringw("maxAngleDegrees") == file->getNodeName())
                           maxAngleDegrees = file->getAttributeValueAsInt(L"value");

                         // <minStartSize>
                         else if(stringw("minStartSize") == file->getNodeName())
                         {
                            minStartSize = dimension2df( file->getAttributeValueAsFloat(L"width"),
                                                         file->getAttributeValueAsFloat(L"height"));
                         }

                         // <maxStartSize>
                         else if(stringw("maxStartSize") == file->getNodeName())
                         {
                            maxStartSize = dimension2df( file->getAttributeValueAsFloat(L"width"),
                                                         file->getAttributeValueAsFloat(L"height"));
                         }

                         break;

                      case io::EXN_ELEMENT_END:

                         // </PointEmitter>
                         if(stringw("PointEmitter") == file->getNodeName())
                           doneParsing = true;

                         break;

                      default:

                         break;
                   }
                }

                // We create the emitter.
                component->setPointEmitter(direction, minParticlesPerSecond, maxParticlesPerSecond,
                             minStartColor, maxStartColor, lifeTimeMin, lifeTimeMax,
                             maxAngleDegrees, minStartSize, maxStartSize);
             }

             // <RingEmitter>
             else if(stringw("RingEmitter") == file->getNodeName())
             {
                // Retrieve required variables from internal loop.
                vector3df center;
                f32 radius;
                f32 ringThickness;
                vector3df direction = vector3df(0.0f, 0.03f, 0.0f);
                u32 minParticlesPerSecond = 5;
                u32 maxParticlesPerSecond = 10;
                SColor minStartColor = SColor(255, 0, 0, 0);
                SColor maxStartColor = SColor(255, 255, 255, 255);
                u32 lifeTimeMin = 2000;
                u32 lifeTimeMax = 4000;
                s32 maxAngleDegrees = 0;
                dimension2df minStartSize = dimension2df(5.0f, 5.0f);
                dimension2df maxStartSize = dimension2df(5.0f, 5.0f);

                bool doneParsing = false;

                while(file->read() && !doneParsing)
                {
                   switch(file->getNodeType())
                   {
                      case io::EXN_ELEMENT:

                         // <center>
                         if(stringw("center") == file->getNodeName())
                         {
                            center = vector3df( file->getAttributeValueAsFloat(L"x"),
                                                file->getAttributeValueAsFloat(L"y"),
                                                file->getAttributeValueAsFloat(L"z") );
                         }

                         // <radius>
                         else if(stringw("radius") == file->getNodeName())
                           radius = file->getAttributeValueAsFloat(L"value");

                         // <ringThickness>
                         else if(stringw("ringThickness") == file->getNodeName())
                           ringThickness = file->getAttributeValueAsFloat(L"value");

                         // <direction>
                         else if(stringw("direction") == file->getNodeName())
                         {
                            direction = vector3df( file->getAttributeValueAsFloat(L"x"),
                                                   file->getAttributeValueAsFloat(L"y"),
                                                   file->getAttributeValueAsFloat(L"z") );
                         }

                         // <minParticlesPerSecond>
                         else if(stringw("minParticlesPerSecond") == file->getNodeName())
                           minParticlesPerSecond = file->getAttributeValueAsInt(L"value");

                         // <maxParticlesPerSecond>
                         else if(stringw("maxParticlesPerSecond") == file->getNodeName())
                           maxParticlesPerSecond = file->getAttributeValueAsInt(L"value");

                         // <minStartColor>
                         else if(stringw("minStartColor") == file->getNodeName())
                         {
                            minStartColor = SColor( file->getAttributeValueAsInt(L"a"),
                                                    file->getAttributeValueAsInt(L"r"),
                                                    file->getAttributeValueAsInt(L"g"),
                                                    file->getAttributeValueAsInt(L"b") );
                         }

                         // <maxStartColor>
                         else if(stringw("maxStartColor") == file->getNodeName())
                         {
                            maxStartColor = SColor( file->getAttributeValueAsInt(L"a"),
                                                    file->getAttributeValueAsInt(L"r"),
                                                    file->getAttributeValueAsInt(L"g"),
                                                    file->getAttributeValueAsInt(L"b") );
                         }

                         // <lifeTimeMin>
                         else if(stringw("lifeTimeMin") == file->getNodeName())
                           lifeTimeMin = file->getAttributeValueAsInt(L"value");

                         // <lifeTimeMin>
                         else if(stringw("lifeTimeMax") == file->getNodeName())
                           lifeTimeMax = file->getAttributeValueAsInt(L"value");

                         // <maxAngleDegrees>
                         else if(stringw("maxAngleDegrees") == file->getNodeName())
                           maxAngleDegrees = file->getAttributeValueAsInt(L"value");

                         // <minStartSize>
                         else if(stringw("minStartSize") == file->getNodeName())
                         {
                            minStartSize = dimension2df( file->getAttributeValueAsFloat(L"width"),
                                                         file->getAttributeValueAsFloat(L"height"));
                         }

                         // <maxStartSize>
                         else if(stringw("maxStartSize") == file->getNodeName())
                         {
                            maxStartSize = dimension2df( file->getAttributeValueAsFloat(L"width"),
                                                         file->getAttributeValueAsFloat(L"height"));
                         }

                         break;

                      case io::EXN_ELEMENT_END:

                         // </RingEmitter>
                         if(stringw("RingEmitter") == file->getNodeName())
                           doneParsing = true;

                         break;

                      default:

                         break;
                   }
                }

                // We create the emitter.
                component->setRingEmitter(center, radius, ringThickness, direction,
                             minParticlesPerSecond, maxParticlesPerSecond, minStartColor,
                             maxStartColor, lifeTimeMin, lifeTimeMax, maxAngleDegrees,
                             minStartSize, maxStartSize);
             }

             // <SphereEmitter>
             else if(stringw("SphereEmitter") == file->getNodeName())
             {
                // Retrieve required variables from internal loop.
                vector3df center;
                f32 radius;
                vector3df direction = vector3df(0.0f, 0.03f, 0.0f);
                u32 minParticlesPerSecond = 5;
                u32 maxParticlesPerSecond = 10;
                SColor minStartColor = SColor(255, 0, 0, 0);
                SColor maxStartColor = SColor(255, 255, 255, 255);
                u32 lifeTimeMin = 2000;
                u32 lifeTimeMax = 4000;
                s32 maxAngleDegrees = 0;
                dimension2df minStartSize = dimension2df(5.0f, 5.0f);
                dimension2df maxStartSize = dimension2df(5.0f, 5.0f);

                bool doneParsing = false;

                while(file->read() && !doneParsing)
                {
                   switch(file->getNodeType())
                   {
                      case io::EXN_ELEMENT:

                         // <center>
                         if(stringw("center") == file->getNodeName())
                         {
                            center = vector3df( file->getAttributeValueAsFloat(L"x"),
                                                file->getAttributeValueAsFloat(L"y"),
                                                file->getAttributeValueAsFloat(L"z") );
                         }

                         // <radius>
                         else if(stringw("radius") == file->getNodeName())
                           radius = file->getAttributeValueAsFloat(L"value");

                         // <direction>
                         else if(stringw("direction") == file->getNodeName())
                         {
                            direction = vector3df( file->getAttributeValueAsFloat(L"x"),
                                                   file->getAttributeValueAsFloat(L"y"),
                                                   file->getAttributeValueAsFloat(L"z") );
                         }

                         // <minParticlesPerSecond>
                         else if(stringw("minParticlesPerSecond") == file->getNodeName())
                           minParticlesPerSecond = file->getAttributeValueAsInt(L"value");

                         // <maxParticlesPerSecond>
                         else if(stringw("maxParticlesPerSecond") == file->getNodeName())
                           maxParticlesPerSecond = file->getAttributeValueAsInt(L"value");

                         // <minStartColor>
                         else if(stringw("minStartColor") == file->getNodeName())
                         {
                            minStartColor = SColor( file->getAttributeValueAsInt(L"a"),
                                                    file->getAttributeValueAsInt(L"r"),
                                                    file->getAttributeValueAsInt(L"g"),
                                                    file->getAttributeValueAsInt(L"b") );
                         }

                         // <maxStartColor>
                         else if(stringw("maxStartColor") == file->getNodeName())
                         {
                            maxStartColor = SColor( file->getAttributeValueAsInt(L"a"),
                                                    file->getAttributeValueAsInt(L"r"),
                                                    file->getAttributeValueAsInt(L"g"),
                                                    file->getAttributeValueAsInt(L"b") );
                         }

                         // <lifeTimeMin>
                         else if(stringw("lifeTimeMin") == file->getNodeName())
                           lifeTimeMin = file->getAttributeValueAsInt(L"value");

                         // <lifeTimeMin>
                         else if(stringw("lifeTimeMax") == file->getNodeName())
                           lifeTimeMax = file->getAttributeValueAsInt(L"value");

                         // <maxAngleDegrees>
                         else if(stringw("maxAngleDegrees") == file->getNodeName())
                           maxAngleDegrees = file->getAttributeValueAsInt(L"value");

                         // <minStartSize>
                         else if(stringw("minStartSize") == file->getNodeName())
                         {
                            minStartSize = dimension2df( file->getAttributeValueAsFloat(L"width"),
                                                         file->getAttributeValueAsFloat(L"height"));
                         }

                         // <maxStartSize>
                         else if(stringw("maxStartSize") == file->getNodeName())
                         {
                            maxStartSize = dimension2df( file->getAttributeValueAsFloat(L"width"),
                                                         file->getAttributeValueAsFloat(L"height"));
                         }

                         break;

                      case io::EXN_ELEMENT_END:

                         // </SphereEmitter>
                         if(stringw("SphereEmitter") == file->getNodeName())
                           doneParsing = true;

                         break;

                      default:

                         break;
                   }
                }

                // We create the emitter.
                component->setSphereEmitter(center, radius, direction, minParticlesPerSecond,
                             maxParticlesPerSecond, minStartColor, maxStartColor, lifeTimeMin,
                             lifeTimeMax, maxAngleDegrees, minStartSize, maxStartSize);
             }

             break;

          case io::EXN_ELEMENT_END:

             // </ParticleSysComponent>
             if(stringw("ParticleSysComponent") == file->getNodeName())
               return true;

             break;

          default:

             break;
       }

   }

   // The code should never get here.
   return false;
}

// End of File
